# waveplugs/watcher.py
#
#

""" watch waves through xmpp. a wave is called a channel here. """

## gozerlib imports

from gozerlib.commands import cmnds
from gozerlib.callbacks import callbacks, gn_callbacks
from gozerlib.persist import PlugPersist
from gozerlib.gozernet.bot import GozerNetBot
from gozerlib.fleet import fleet
from gozerlib.utils.exception import handle_exception

## basic imports

import copy
import logging

cpy = copy.deepcopy

class Watched(PlugPersist):

    """ Watched object contains channels and subscribers. """

    def __init__(self, filename):
        PlugPersist.__init__(self, filename)
        self.data.channels = self.data.channels or {}
        self.data.whitelist = self.data.whitelist or []
        self.data.descriptions = self.data.descriptions or {}

    def subscribe(self, botname, channel, jid):

        """ subscrive a jid to a channel. """ 

        jid = unicode(jid)

        if not self.data.channels.has_key(channel):
            self.data.channels[channel] = []

        if not [botname, jid] in self.data.channels[channel]:
            self.data.channels[channel].append([botname, jid])
            self.save()

        return True

    def unsubscribe(self, botname, channel, jid):

        """ unsubscribe a jid from a channel. """ 

        try:
            self.data.channels[channel].remove([botname, unicode(jid)])

        except (KeyError, TypeError):
            return False

        self.save()
        return True

    def subscribers(self, channel):
        try:
            return self.data.channels[channel]
        except KeyError:
            return []

    def check(self, channel):

        """ check if channel is available (in whitelist) AND has subscribers. """

        return self.data.channels.has_key(channel)

    def channels(self, channel):

        """ return all subscribers of a channel. """

        try:
            return self.data.channels[channel]
        except KeyError:
            return None

    def enable(self, channel):

        """ add channel to whitelist. """

        if not channel in self.data.whitelist:
            self.data.whitelist.append(channel)
            self.save()

    def disable(self, channel):
 
        """ remove channel from whitelist. """

        try:
            self.data.whitelist.remove(channel)
        except ValueError:
            return False

        self.save()
        return True

    def available(self, channel):

        """ check if channel is on whitelist. """

        return channel in self.data.whitelist

    def channels(self, channel):

        """ return channels on whitelist. """

        res = []

        for chan, targets in self.data.channels.iteritems():

            if channel in str(targets):
                res.append(chan)

        return res

watched = Watched('channels')

def prewatchcallback(bot, event):

    logging.debug("watcher - pre - %s - %s - %s" % (event.channel, event.userhost, event.txt))
    return watched.check(event.channel) and event.txt

def watchcallback(bot, event):

    if not event.txt:
        return

    #if event.iscallback and not event.isremote:
    #    return

    subscribers = watched.subscribers(event.channel)
    watched.data.descriptions[event.channel] = event.title
    logging.debug("watcher - out - %s - %s" % (str(subscribers), event.txt))

    for item in subscribers:

        try:
            (botname, channel) = item
        except ValueError:
            continue

        watchbot = fleet.byname(botname)

        if watchbot:
            orig = event.nick or event.userhost

            #if orig in [botname, bot.name]:
            #    continue

            if event.cbtype == "OUTPUT":

                try:
                    from gozerlib.gae.wave.waves import Wave
                    wave = Wave(event.channel)
                except ImportError:
                    wave = None

                if wave:
                    txt = u"[%s] %s: %s" % (wave.data.title, event.ruserhost, event.txt)
                else:
                    txt = u"[%s] %s: %s" % (botname, event.ruserhost, event.txt)

            else:
                txt = u"[%s] %s" % (orig, event.txt)

            logging.debug("watcher - %s - %s" % (botname, txt))

            if txt.find('] [') > 1:
                continue

            watchbot.say(channel, txt)

gn_callbacks.add('BLIP_SUBMITTED', watchcallback, prewatchcallback)
callbacks.add('BLIP_SUBMITTED', watchcallback, prewatchcallback)
gn_callbacks.add('PRIVMSG', watchcallback, prewatchcallback)
#callbacks.add('PRIVMSG', watchcallback, prewatchcallback)
gn_callbacks.add('OUTPUT', watchcallback, prewatchcallback)
callbacks.add('OUTPUT', watchcallback, prewatchcallback)
gn_callbacks.add('MESSAGE', watchcallback, prewatchcallback)

def handle_watcherstart(bot, event):

    if not event.rest:
        target = event.origin
    else:
        target = event.rest

    if '@' in target and not event.userhost == target:
        event.reply('you are not allowed to watch %s' % target)
        return

    watched.subscribe(bot.name, event.rest, event.channel)
    event.done()

    try:
        wave = Wave(event.rest)

        if wave:

            wavebot = fleet.byname('wavebot')

            if wavebot:
                wave.say(wavebot, "%s is now watching %s" % (event.channel, event.rest))

    except Exception, ex:
        handle_exception()

cmnds.add('watcher-start', handle_watcherstart, 'USER')

def handle_watcherstop(bot, event):

    if not event.rest:
        target = event.origin
    else:
        target = event.rest

    watched.unsubscribe(bot.name, target, event.channel)
    event.done()

cmnds.add('watcher-stop', handle_watcherstop, 'USER')

def handle_watcherchannels(bot, event):
    chans = watched.channels(event.channel)

    if chans:
        res = []

        for chan in chans: 

            try:
                res.append("%s (%s)" % (chan, watched.data.descriptions[chan]))
            except KeyError:
                res.append(chan)

        event.reply("channels watched on %s: " % event.channel, res)

cmnds.add('watcher-channels', handle_watcherchannels, ['USER'])

def handle_watcherlist(bot, event):
    event.reply("watchers for %s: " % event.channel, watched.subscribers(event.channel))

cmnds.add('watcher-list', handle_watcherlist, ['USER'])
